#include "FileControl_Test.h"

#include "server/file/FileControl.h"
#include "server/misc/Config.h"
#include <Poco/File.h>
#include <Poco/Runnable.h>
#include <Poco/ThreadPool.h>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <string>
/*********************************************************/
std::string FileControlTest::name()
{
	return("FileControl");
}
/*********************************************************/
bool FileControlTest::runUnitTests()
{
	bool result = true;

	if ( !paddingBytesTest() ) result = false;
	if ( !readWriteLockTest() ) result = false;

	return( result ) ;
}
/*********************************************************/
bool FileControlTest::readWriteLockTest()
{
	// We need some test classes to achieve the multithreading needed in this test
	// The reader class that will read chunks from the repo
	class reader : public Poco::Runnable {
	private:
		void run() {
			try {
				FileControl& 		fCtrl = FileControl::Instance();
				for ( int i = 0; i<10000; i++ ) {
					std::string data = fCtrl.getChunk("test.txt", 0);
				}
			} catch(std::exception& e) {
				std::cout << "Reader: failed with exception: " << e.what() << std::endl;
			} catch(...) {
				std::cout << "Reader: Failed with exception!" << std::endl;
			}
		}
	};

	// The writer class, that will write chunks to the repo
	class writer : public Poco::Runnable {
	private:
		void run() {
			try {
				FileControl& 		fCtrl = FileControl::Instance();
				for ( int i = 0; i<100; i++ ) {
					std::ostringstream oss;
					oss << "Hello World!" << i;
					fCtrl.addChunk("test.txt", 0, oss.str(), oss.str().length());
				}
			} catch(std::exception& e) {
				std::cout << "Writer: failed with exception: " << e.what() << std::endl;
			} catch(...) {
				std::cout << "Writer: Failed with exception!" << std::endl;
			}
		}
	};

	std::cout << "Running : readWriteLockTest()";
	try {
		Poco::ThreadPool	tPool;
		FileControl& 		fCtrl = FileControl::Instance();
		fCtrl.addChunk("test.txt", 0, "Hello World!", 12);

		// Start 5 readers and 2 writers!
		reader	r1, r2, r3, r4, r5;
		writer 	w1, w2;
		tPool.start(r1);
		tPool.start(r2);
		tPool.start(w1);
		tPool.start(r3);
		tPool.start(r4);
		tPool.start(w2);
		tPool.start(r5);

		tPool.joinAll();		// Wait for completion

		// In any case we should find a consistant data string: "Hello World!99" as data
		std::string data = fCtrl.getChunk("test.txt", 0);
		if ( !data.compare("Hello World!99") ) {
			std::cout << "... failed! inconsistant data after access by multiple threads!" << std::endl;
			return(false);
		}

		std::cout << "...success!" << std::endl;
		return( true );
	} catch(std::exception& e) {
		std::cout << "... failed! with exception: " << e.what() << std::endl;
		return( false );
	}
}
/*********************************************************/
bool FileControlTest::paddingBytesTest()
{
	std::cout << "Running : paddingBytesTest()";
	try {
		FileControl& fCtrl = FileControl::Instance();
		Config& cfg = Config::Instance();

		// We need to force a new repository!
		std::string repo = cfg.getFileRepository();
		repo.append(".ind");
		if (Poco::File(repo).exists()) {
			Poco::File(repo).remove();
		}
		cfg.setChunkSize(20);
		cfg.setMaxArchiveSize(2000);
		fCtrl.init();				// will create a new archive with specified parameters

		std::string data = "This is a test";	// This data is shorter then a single chunk of data so it will be padded with some bytes
		fCtrl.addChunk("testfile.txt", 0, data, 14);
		
		std::string result = fCtrl.getChunk("testfile.txt", 0);

		if ( !data.compare(result) ) {
			std::cout << "... failed! Data not identical!" << std::endl;
			return( false );
		}
		
		std::cout << "... success!" << std::endl;
		return( true );
	} catch( std::exception& e ) {
		std::cout << "... failed with exception: " << e.what() << std::endl;
		return( false );
	}
}
